package generator;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.util.Properties;


public class SQLGeneratorV3 {
	private TypeMapper mapper;
	
	public SQLGeneratorV3(TypeMapper mapper) {
		this.mapper = mapper;
	}
	
	public SQLGeneratorV3() {
		Properties properties = new Properties();
		try {
			properties.load(new FileInputStream("conf.properties"));
		} 
		catch (IOException e) {
			e.printStackTrace();
		}
		
		String className = properties.getProperty("mapper");
		Class<?> c = null;
		try {
			 c = Class.forName(className);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		
		Class<? extends TypeMapper> typeMapperClass = null;
		if(TypeMapper.class.isAssignableFrom(c)) {
			typeMapperClass = c.asSubclass(TypeMapper.class);
		}
		
		try {
			mapper = typeMapperClass.newInstance();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
	}


	/**
	 * Gera uma instrucao de SQL para criar uma tabela para uma dada classe 
	 * @param clazz a classe
	 * @return a instrucao CREATE TABLE
	 */
	public String generateCreateTable(Class<?> clazz) {
		StringBuffer sql = new StringBuffer("CREATE TABLE ");
		sql.append(clazz.getSimpleName() + " (");
		Field[] fields = clazz.getDeclaredFields();
		for(int i = 0; i < fields.length; i++) {
			Field f = fields[i];
			Annotation primaryKeyAnn = f.getAnnotation(PrimaryKey.class);
			Annotation fieldSizeAnn = f.getAnnotation(FieldSize.class);
			
			Class<?> type = f.getType();
			String name = f.getName();
			if(i != 0)
				sql.append(", ");
			sql.append(name + " " +  mapper.obtainType(type, (FieldSize) fieldSizeAnn));
			
			if(primaryKeyAnn != null)
				sql.append(" PRIMARY KEY");
		}

		sql.append(")");

		return sql.toString();
	}

	/**
	 * Gera uma instrucao de SQL para inserir uma linha 
	 * (coerente com o generateCreateTable)
	 * 
	 * @param object o objecto a inserir
	 * @return a instrucao INSERT
	 */
	public String generateInsert(Object object) {
		StringBuffer sql = new StringBuffer("INSERT INTO ");
		Class<?> clazz = object.getClass();
		sql.append(clazz.getSimpleName());
		sql.append(" (");
		Field[] fields = clazz.getDeclaredFields();
		for(int i = 0; i < fields.length; i++) {
			Field f = fields[i];
			if(i != 0)
				sql.append(", ");
			sql.append(f.getName());
		}
		sql.append(") VALUES (");
		for(int i = 0; i < fields.length; i++) {
			Field f = fields[i];
			f.setAccessible(true);
			Object obj = null;
			try {
				obj = f.get(object);
			} catch (Exception e) {
				e.printStackTrace();
			} 

			if(i != 0)
				sql.append(", ");

			sql.append(convertValue(obj));
		}

		sql.append(")");
		return sql.toString();
	}



	private String convertValue(Object obj) {
		if(obj == null)
			return "NULL";
		else {
			String text = obj.toString();
			if(obj.getClass().equals(String.class)) {
				text = "'" + text + "'";
			}
			return text;
		}
	}
}
